package moodish.comm;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;

import moodish.comm.ServerSideMessage.Type;


/**
 * This class represents a Thread that will handle the messages received from the clients.
 * 
 * @author Filipe Afonso, Tiago Ribeiro
 * @version 1.0
 */


public class DealWithClient extends Thread {
	private Map<String, ObjectOutputStream> outChannels;
	private Socket socket;
	private String nickname; 
	private ObjectInputStream in;
	private LinkedBlockingQueue<MoodishServerSideMessage>  incomingMessages;

	/**
	 * Construct's a new {@link DealWithClient} thread.
	 *
	 * @param outChannels,the output streams of every connected client to the server.
	 * @param socket, the new socket created to handle this client's communication.
	 * @param incomingMessages, the server list of  incoming messages.
	 */
	public DealWithClient(Map<String, ObjectOutputStream> outChannels, Socket socket,
			LinkedBlockingQueue<MoodishServerSideMessage> incomingMessages) {
		super();
		assert outChannels !=null;
		assert !socket.isClosed() && socket.isBound();
		assert incomingMessages !=null;
		this.outChannels=outChannels;
		this.socket=socket;
		this.incomingMessages = incomingMessages;
	}
	/**
	 * This method starts the thread, its main objective is to receive a message from the client and
	 * pass it along to the server, by putting said message in a
	 * {@link LinkedBlockingQueue} {@code incomingMessages}.
	 * It expects the first message to be an CONNECTED,
	 * it uses the nickname as a key on that message to to add a new pair of output stream and its key.
	 * Once the clients output stream has been removed from the {@code outputChannels} the thread stops,
	 * and closes the {@code socket}.
	 */
	@Override
	public void run() {
		try {
			in = new ObjectInputStream(socket.getInputStream());
			//this first message should be a CLIENT_CONNECTED, the following code,
			//is just used to keep track of which nickname belongs to the output stream.
			MoodishServerSideMessage message = (MoodishServerSideMessage) in.readObject();
			if(message.getType().equals(Type.CLIENT_CONNECTED)){
				assert message.getClientNickname() != null && !message.getClientNickname().isEmpty();
				boolean destroy = false;
				nickname = message.getClientNickname();
				if(!outChannels.containsKey(nickname)){
				outChannels.put(nickname, new ObjectOutputStream(socket.getOutputStream()));
				}else {
					socket.close();
					destroy  = true;
				}
				incomingMessages.put(message);
				while (outChannels.containsKey(nickname) && !destroy) {
					incomingMessages.put((MoodishServerSideMessage) in.readObject());
				}
			}
		} catch (IOException e) {
			outChannels.remove(nickname);
			System.out.println("Failed to get output from socket, remove it from out channels.");
		} catch (ClassNotFoundException e) {
			System.out.println("Failed to receive a MoodishServerMessage");
		} catch (InterruptedException e) {
			System.out.println("Failed to put new message into incomingMessages list");
		}  finally {
			try {
				socket.close();
			} catch (IOException e) {
				System.out.println("Failed to close the socket");
			}
		}
	}
}